#include "ActionAttack.h"
#include "NPCEntity.h"
#include "World.h"
#include "Map.h"
#include "Steering.h"

ActionAttack::ActionAttack()
{
	executer__ = 0 ; 
	Memory::meminfo_t fake ;
	fake.timeSinceSeen = 100000 ;
	p_target__ = std::pair<Entity*,Memory::meminfo_t>(0,fake) ;
	timeToSend__ = 0 ;
	timeToAttack__ = 0 ;

}

ActionAttack::~ActionAttack()
{
}

bool ActionAttack::execute(Entity* executer)
{
	executer__ = executer ;
	timeToSend__ += World::getWorld()->elapsedTime();
	timeToAttack__+=World::getWorld()->elapsedTime();
	p_target__.second.timeSinceSeen += World::getWorld()->elapsedTime();
	NPCEntity * realExecuter = dynamic_cast<NPCEntity *>(executer__) ;
//	std::cout << "temps de vue : " << p_target__.second.timeSinceSeen << std::endl ;

	if((p_target__.first == 0))
	{
		std::pair<Entity*,Memory::meminfo_t> p_target = realExecuter->getMemory()->getNearestHostilePair(executer__) ;
		if(!realExecuter->getMemory()->isEmptyMemory(p_target))
		{
			p_target__.second.position = p_target.second.position ;
			p_target__.second.timeSinceSeen = p_target.second.timeSinceSeen ;
			if(p_target.second.timeSinceSeen <= 1)
			{
				p_target__.first = p_target.first ;
				p_target__.second.timeSinceSeen = 0 ;
			}
			else
			{
				p_target__.first = 0 ;
			}
		
		}
		else
		{
			return true ;
		}
	}

	if((p_target__.first != 0) && (p_target__.second.timeSinceSeen <= 1))
	{

		float maxDist = dynamic_cast<AnimatedEntity*>(p_target__.first)->getMeshNode()->getBoundingBox().getExtent().getLength() ;
		if (p_target__.first->getNode()->getPosition().getDistanceFrom(executer__->getNode()->getPosition()) > maxDist)
		{
			Steering::Seek(realExecuter, p_target__.first);
//			std::cout << "using senses " << std::endl ;
		}
		else
		{
			if(timeToSend__ >= 2.0f)
			{
				// sending messages to all allies
				std::map<Entity*, Memory::meminfo_t> allies = realExecuter->getMemory()->getMemoryByHostility(Hostility::ALLIED) ;
	
				std::map<Entity*,Memory::meminfo_t>::iterator it = allies.begin();
				while(it != allies.end())
				{
					std::pair<Entity*,Memory::meminfo_t> currentMemory = *it ;
					std::string type = p_target__.first->getType().c_str();
					realExecuter->sendMessage(currentMemory.first,"Under_Attack",type,p_target__.first->getNode()->getPosition()); 
					//std::cout << "envoi de messages aux allies " << std::endl;
					it++;
				}
				
				realExecuter->sendMessage(p_target__.first,"Attack") ;
				timeToSend__ = 0 ;
			}
			
			if(timeToAttack__>=1)
            		{
			     realExecuter->setAnimation(EMAT_ATTACK, true) ;
			     dynamic_cast<LivingEntity*>(p_target__.first)->removeLife(realExecuter->getAttribute(L"damage").getValue()) ;
			     timeToAttack__=0;
			}
            			Steering::Face(realExecuter,p_target__.first->getNode()->getPosition()) ;			
				p_target__.second.timeSinceSeen = 0 ;
		}

		if(dynamic_cast<LivingEntity*>(p_target__.first)->isDead())
		{
			realExecuter->getMemory()->timeToForget(p_target__.first) ;
			realExecuter->setAnimation(EMAT_STAND, true) ;
			return true ;
		}
		else
		{
			p_target__.first = 0 ;
			return false ;
		}

	}
	else
	{
		if((p_target__.second.timeSinceSeen <= 30) || ((realExecuter->getNode()->getPosition().getDistanceFrom(p_target__.second.position)) < 100))
		{
			if(timeToSend__ >= 2.0f)
			{
				// sending messages to all allies
				std::map<Entity*, Memory::meminfo_t> allies = realExecuter->getMemory()->getMemoryByHostility(Hostility::ALLIED) ;
				std::map<Entity*,Memory::meminfo_t>::iterator it = allies.begin();
				while(it != allies.end())
				{
					std::pair<Entity*,Memory::meminfo_t> currentMemory = *it ;
					std::string type = p_target__.second.type.c_str() ;
					realExecuter->sendMessage(currentMemory.first,"Under_Attack",type,p_target__.second.position); 
					//std::cout << "envoi de messages aux allies " << std::endl;
					it++;
				}
				timeToSend__ = 0 ;
			}

			std::pair<Entity*,Memory::meminfo_t> p_target = realExecuter->getMemory()->getNearestHostilePair(executer__) ;
			p_target__ = p_target ;
			Steering::Seek(realExecuter, p_target__.second.position);
			//std::cout << "using memory, target at " << p_target__.second.position.X << " " << p_target__.second.position.Y << std::endl ;
			if((realExecuter->getNode()->getPosition().getDistanceFrom(p_target__.second.position)) < 100)
			{
				//if(p_target__.second.timeSinceSeen <= 1)
				//{
					//std::cout << "3eme return true : le cas bizarre" << std::endl ;
					return false ;
				//}
			}
			//return false ;
		}
		else
		{
				std::cout << "Dernier return true : l'ennemi a fui " << std::endl ;
				return true ;
		}
	}

	return true;
}


bool ActionAttack::checkConditions()
{
	if(executer__ != 0)
	{
		NPCEntity * realExecuter = dynamic_cast<NPCEntity *>(executer__) ;
		// the attack plan has a chance to be cancelled if the life is critical
		if(realExecuter->isLifeCritical())
		{
			World * w = World::getWorld() ;
			// random float
			float rand = w->randf() ;
			float bandingModifier = realExecuter->getDesires()->getDesireValue("Banding") ;
			

			// probability for cancelling 
			if(rand < (0.1 + bandingModifier))
			{
				return false ;
				std::cout << "plan cancelled" << std::endl; 
			}
			else
			{
				return true ;
			}
		}
	}

     return true ;    
}








